function foo(a, b, c = 0) {
  console.log(a + b + c);
  console.log(this);
}

const obj = {
  a: 123,
};

// foo.call(obj, 1, 3); // 4 obj
// foo.apply(obj, [2, 4]); // 6 obj
// foo.bind(obj, 3).bind(obj, 5)(6); // 8 obj

Function.prototype.myCall = function (context = window, ...args) {
  if (this === Function.prototype) {
    return undefined; // 用于防止 Function.prototype.myCall() 直接调用
  }
  context = context || window;
  const fn = Symbol();
  context[fn] = this;
  const result = context[fn](...args);
  delete context[fn];
  return result;
};

Function.prototype.myApply = function (context = window, args) {
  if (this === Function.prototype) {
    return undefined;
  }
  if (!Array.isArray(args)) {
    throw new TypeError("参数类型错误");
  }
  context = context || window;
  const fn = Symbol();
  context[fn] = this;
  const result = context[fn](...args);
  delete context[fn];
  return result;
};set

Function.prototype.myBind = function (context = window, ...args) {
  if (this === Function.prototype) {
    throw new TypeError("Error");
  }
  context = context || window;
  const _this = this;
  return function F(...args2) {
    console.log(...args)
    console.log(...args2)
    if (this instanceof F) {
      return new _this(...args, ...args2);
    }
    const result = _this.apply(context, args.concat(args2));
    return result;
  };
};
// foo.myCall(obj, 1, 3); // 4 obj
// foo.myApply(obj, [2, 4]); // 4 obj
foo.myBind(obj, 3).myBind(obj, 5)(6); // 8 obj
